package demo.Map;

import java.util.*;

/**
 * Map是一种依照键（key）存储元素的容器，键（key）很像下标，在List中下标是整数。在Map中键（key）可以使任意类型的对象。Map中不能有重复的键（Key），每个键（key）都有一个对应的值（value）。
 * 一个键（key）和它对应的值构成map集合中的一个元素。
 * Map中的元素是两个对象，一个对象作为键，一个对象作为值。键不可以重复，但是值可以重复。
 *
 * Map与Collection在集合框架中属并列存在
 * Map存储的是键值对
 * Map存储元素使用put方法，Collection使用add方法
 * Map集合没有直接取出元素的方法，而是先转成Set集合，在通过迭代获取元素
 * Map集合中键要保证唯一性
 * 也就是Collection是单列集合, Map 是双列集合。
 *
 * 总结:
 * Map一次存一对元素, Collection 一次存一个。Map 的键不能重复，保证唯一。
 * Map 一次存入一对元素,是以键值对的形式存在.键与值存在映射关系.一定要保证键的唯一性.
 * 查看api文档:
 * interface Map<K,V>
 * K - 此映射所维护的键的类型
 * V - 映射值的类型
 *
 * Map学习体系：
 *  ---| Map  接口    将键映射到值的对象。一个映射不能包含重复的键；每个键最多只能映射到一个值。
 * 			---| HashMap  采用哈希表实现，所以无序
 *             ---| TreeMap   可以对健进行排序
 *
 * ---|Hashtable:
 * 底层是哈希表数据结构，线程是同步的，不可以存入null键，null值。
 * 效率较低，被HashMap 替代。
 * ---|HashMap:
 * 底层是哈希表数据结构，线程是不同步的，可以存入null键，null值。
 * 要保证键的唯一性，需要覆盖hashCode方法，和equals方法。
 * ---| LinkedHashMap：
 * 该子类基于哈希表又融入了链表。可以Map集合进行增删提高效率。
 * ---|TreeMap:
 * 底层是二叉树数据结构。可以对map集合中的键进行排序。需要使用Comparable或者Comparator 进行比较排序。return 0，来判断键的唯一性。
 */
public class MapTest {
    /**
     * 1、添加：
     * 	1、V put(K key, V value)    （可以相同的key值，但是添加的value值会覆
     * 盖前面的，返回值是前一个，如果没有就返回null）
     * 	2、putAll(Map<? extends K,? extends V> m)  从指定映射中将所有映射关
     * 系复制到此映射中（可选操作）。
     * 2、删除
     * 	1、remove()    删除关联对象，指定key对象
     * 	2、clear()     清空集合对象
     * 3、获取
     *      1：value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候，返
     * 回的是null。
     *
     * 3、判断：
     * 	1、boolean isEmpty()   长度为0返回true否则false
     *     2、boolean containsKey(Object key)  判断集合中是否包含指定的key
     * 3、boolean containsValue(Object value)  判断集合中是否包含指定的value
     * 4、长度：
     * Int size（）
     * @param args
     */
    public static void main(String[] args) {
        // 定义一个Map的容器对象
        Map<String, Integer > map1 = new HashMap<String, Integer >();
        map1.put("jack", 20);
        map1.put("rose", 18);
        map1.put("lucy", 17);
        map1.put("java", 25);
        System.out.println(map1);
        // 添加重复的键值（值不同）,会返回集合中原有（重复键）的值，		 System.out.println(map1.put("jack", 30)); //20

        Map<String, Integer> map2 = new HashMap<String, Integer>();
        map2.put("张三丰", 100);
        map2.put("虚竹", 20);
        System.out.println("map2:" + map2);
        // 从指定映射中将所有映射关系复制到此映射中。
        map1.putAll(map2);
        System.out.println("map1:" + map1);
        //
    }

    public static void delete()
    {
        // 删除：
        // remove() 删除关联对象，指定key对象
        // clear() 清空集合对象

        Map<String, Integer> map1 = new HashMap<String, Integer>();
        map1.put("jack", 20);
        map1.put("rose", 18);
        map1.put("lucy", 17);
        map1.put("java", 25);
        System.out.println(map1);
// 指定key，返回删除的键值对映射的值。
        System.out.println("value:" + map1.remove("java"));
        map1.clear();
        System.out.println("map1:" + map1);
    }

    public static void get()
    {
        // 获取：
        // V get(Object key) 通过指定的key对象获取value对象
        // int size() 获取容器的大小
        Map<String, Integer> map1 = new HashMap<String, Integer>();
        map1.put("jack", 20);
        map1.put("rose", 18);
        map1.put("lucy", 17);
        map1.put("java", 25);
        System.out.println(map1);
        // V get(Object key) 通过指定的key对象获取value对象
        // int size() 获取容器的大小
        System.out.println("value:" + map1.get("jack"));
        System.out.println("map.size:" + map1.size());
    }

    public static void isEmpty()
    {
        // 判断：
        // boolean isEmpty() 长度为0返回true否则false
        // boolean containsKey(Object key) 判断集合中是否包含指定的key
        // boolean containsValue(Object value)

        Map<String, Integer> map1 = new HashMap<String, Integer>();
        map1.put("jack", 20);
        map1.put("rose", 18);
        map1.put("lucy", 17);
        map1.put("java", 25);
        System.out.println(map1);
        System.out.println("isEmpty:" + map1.isEmpty());
        System.out.println("containskey:" + map1.containsKey("jack"));
        System.out.println("containsvalues:" + map1.containsValue(100));
    }

    /**
     * 遍历Map的方式
     * @desc MapForeach类。
     * 1、将map 集合中所有的键取出存入set集合。
     * 		Set<K> keySet()   返回所有的key对象的Set集合
     *                              再通过get方法获取键对应的值。
     * 2、 values() ，获取所有的值.
     * 		Collection<V> values()不能获取到key对象
     * 3、 Map.Entry对象  推荐使用   重点
     * 		Set<Map.Entry<k,v>> entrySet()
     * 将map 集合中的键值映射关系打包成一个对象
     * Map.Entry对象通过Map.Entry 对象的getKey，
     * getValue获取其键和值。
     */
    private static class MapForeach {

        public static void main(String[] args) {
            /*第一种方式:使用keySet

            将Map转成Set集合（keySet()），通过Set的迭代器取出Set集合中的每一个元素（Iterator）就是Map集合中的所有的键，再通过get方法获取键对应的值。*/
            Map<Integer, String> map = new HashMap<Integer, String>();
            map.put(1, "aaaa");
            map.put(2, "bbbb");
            map.put(3, "cccc");
            System.out.println(map);

            //
            // 获取方法：
            // 第一种方式: 使用keySet
            // 需要分别获取key和value，没有面向对象的思想
            // Set<K> keySet() 返回所有的key对象的Set集合

            Set<Integer> ks = map.keySet();
            Iterator<Integer> it = ks.iterator();
            while (it.hasNext()) {
                Integer key = it.next();
                String value = map.get(key);
                System.out.println("key=" + key + " value=" + value);
            }

            //第二种方式: 通过values 获取所有值,不能获取到key对象
            // 第二种方式：
            // 通过values 获取所有值,不能获取到key对象
            // Collection<V> values()

            Collection<String> vs = map.values();
            Iterator<String> it2 = vs.iterator();
            while (it2.hasNext()) {
                String value = it2.next();
                System.out.println(" value=" + value);
            }

            /*第三种方式: Map.Entry

            public static interface Map.Entry<K,V>
            通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合。
            Set<Map.Entry<K,V>> entrySet()
            面向对象的思想将map集合中的键和值映射关系打包为一个对象，就是Map.Entry
            ，将该对象存入Set集合，Map.Entry是一个对象，那么该对象具备的getKey，getValue获得键和值。*/

            // 第三种方式： Map.Entry对象 推荐使用 重点
            // Set<Map.Entry<K,V>> entrySet()


            // 返回的Map.Entry对象的Set集合 Map.Entry包含了key和value对象
            Set<Map.Entry<Integer, String>> es = map.entrySet();

            Iterator<Map.Entry<Integer, String>> it3 = es.iterator();

            while (it3.hasNext()) {

                // 返回的是封装了key和value对象的Map.Entry对象
                Map.Entry<Integer, String> en = it3.next();

                // 获取Map.Entry对象中封装的key和value对象
                Integer key = en.getKey();
                String value = en.getValue();

                System.out.println("key=" + key + " value=" + value);
            }


        }


    }

}
